#!/usr/bin/perl -w

#Copyright (c) 2019 Alibaba Group Holding Limited
#
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use Getopt::Long;
    $Getopt::Long::ignorecase = 0;
use File::Copy;
use Cwd;
use FileHandle;
use File::Basename;
use Term::ANSIColor;
use strict;
no strict 'refs';
my $wujian100_open_PATH = `pwd`;
chomp($wujian100_open_PATH);
#每次修改文件主目录时都需要修改该路径值
$wujian100_open_PATH =~ s/zlsjb100_plus.*/zlsjb100_plus-v9.1.2.1_tee_ree\//;

#区分工作区的两个核的工程文档路径
my $MAKE_PATH_1 ="ree_lib";
my $MAKE_PATH_2 ="tee_lib";
my $com_dir = `pwd`;
chomp($com_dir);
my $work;
#指定工作目录
$work = "$wujian100_open_PATH\/workdir";
chdir($work);
my @file2del;
my $dir = `pwd`;
if($dir =~ /workdir$/) {
	@file2del = qx(ls);
	foreach(@file2del){
		chomp($_);
		if("$_" ne "CVS"){
			!system("rm -rf $_") or die "can't rm";
		}
	}
}
else {
	print "Error when change directory to workdir!";
	exit(1);
}
print "\nStep1 (Remove all things in current 'workdir') is finished!\n";

my %Opt;
if(!&GetOptions
	(\%Opt,
		'--h',	                #Print help message
		'--nodump',             #Disable the waveform dump function in VCS simulation
		'--sim_tool:s',         #Specify the simulation tools, support vcs and iverilog
		'--nomnt'))              #disable mnt module when running tb
{
	&print_usage();
	exit(1);
}

if($Opt{'h'}) {
	&print_usage();
	exit(1);
}


my $s_vcs = 0;
my $s_iverilog = 0;
if(!defined($Opt{'sim_tool'}) || ($Opt{'sim_tool'} eq "vcs")){
	$s_vcs = 1;
}elsif($Opt{'sim_tool'} eq "iverilog"){
	$s_iverilog = 1;
}
if(!$s_vcs && !$s_iverilog){
	print "Invalid simulation tool! Support vcs or iverilog.\n";
	exit(1);
}


#与tb中$dumpfile中的内容联动
my $dump_sim = "";
if(defined($Opt{'nodump'})){
	$dump_sim = "+define+NO_DUMP";
}

my $s_nomnt = 0;
if(defined($Opt{'nomnt'})){
	$s_nomnt = 1;
}
my $mnt_sim = "";
if ($s_nomnt == 1) {
	$mnt_sim = "+define+NO_MONITOR";
}

my $cpu_model = "e902";

my $hgpr= "";
my $mad = 1;

my $cpu_model_make;
my $dahb_lite = 0;

if("$cpu_model" eq "e902"){
	my $temp_line;
	my $flag_902 = 1;
	my $bctm_902 = 0;
	my $iabh_lite_902 = 1;
	my $dabh_lite_902 = 0;
           $cpu_model_make = "e902m";
}

chdir($com_dir);
my $path;
my $case;
my $case_file;
my $case_make;
my $had_v;
my @file;

# 通过系统层级在workdir工作区创建两个分立的文件夹
!system("mkdir ./$MAKE_PATH_1")or die "can't mkdir $MAKE_PATH_1";
!system("mkdir ./$MAKE_PATH_2")or die "can't mkdir $MAKE_PATH_2";

foreach(@ARGV){
	if(/(.*\/)(.*)/){
		$case_file = $_;
		$path = $1;
		$case = $2;
	}else{
		$case_file = $_;
		$case = $_;
		chomp($path = `pwd`);
	}
	if($case =~ /(.*)\.s/){#如果要添加额外的case文件则需要在这个位置进行更改
		$case_make = $1;
		!system("cp $case_file $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy $case_file to $MAKE_PATH_1";
		!system("cp $case_file $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy $case_file to $MAKE_PATH_2";
		!system("cp $case_file $wujian100_open_PATH/workdir") or die "can't copy $case_file";
		if(($case =~ /.*had.*\.s/) or ($case =~ /.*gpio.*\.s/) or ($case =~ /.*connect.*\.s/) or ($case =~ /.*pulse.*\.s/) or ($case =~ /.*lpmd.*\.s/) or ($case =~ /.*int_ack.*\.s/) or ($case =~ /.*bist.*\.s/) or ($case =~ /.*e902.*nest.*\.s/)){
			$case_file =~ s/\.s/\.v/;
			$had_v = $case;
			$had_v =~ s/\.s/\.v/;
			!system("cp $case_file $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy $case_file to $MAKE_PATH_1";
			!system("cp $case_file $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy $case_file to $MAKE_PATH_2";
			!system("cp $case_file $wujian100_open_PATH/workdir") or die "can't copy $case_file";
		}
	}

	if($case =~ /(.*)\.c/){
		$case_make = $1;
		chomp(@file = `ls $path`);
		foreach(@file){
			if(/CVS/){
				undef $_;
			}else{
				my $file = "$path"."\/"."$_";
				print "the file is $file\n";
				!system("cp $file $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy $case_file to $MAKE_PATH_1";
				!system("cp $file $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy $case_file to $MAKE_PATH_2";
				!system("cp $file $wujian100_open_PATH/workdir") or die "can't copy $case_file";
				if(($case =~ /.*had.*\.c/) or ($case =~ /.*gpio.*\.c/) or ($case =~ /.*pwm.*\.c/) or ($case =~ /.*map_test.*\.c/)  or ($case =~ /.*usi.*\.c/)){
					$case_file =~ s/\.c/\.v/;
					$had_v = $case;
					$had_v =~ s/\.c/\.v/;
					!system("cp $case_file $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy $case_file to $MAKE_PATH_1";
					!system("cp $case_file $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy $case_file to $MAKE_PATH_2";
					!system("cp $case_file $wujian100_open_PATH/workdir") or die "can't copy $case_file";
				}	
			}
			if($_=~/int_ack\w+\.v/){
			  $had_v=$_;
                          print "########$had_v#########\n";	
			}
		}
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_1/clib/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy clib program";
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_2/clib/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy clib program";
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_1/clib/my_clib/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy clib program";
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_1/clib/my_clib/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy clib program";
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_1/clib/*.c $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy clib program";
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_2/clib/*.c $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy clib program";
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_1/clib/my_clib/*.c $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy clib program";
		!system("cp $wujian100_open_PATH/lib/$MAKE_PATH_1/clib/my_clib/*.c $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy clib program";
        !system("cp $wujian100_open_PATH/lib/$MAKE_PATH_1/newlib_wrap/*.c $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy clib program";
        !system("cp $wujian100_open_PATH/lib/$MAKE_PATH_2/newlib_wrap/*.c $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy clib program";
        !system("cp $wujian100_open_PATH/case/flash_control/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy flash program"; 
        !system("cp $wujian100_open_PATH/case/flash_control/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy flash program";
          !system("cp $wujian100_open_PATH/case/iopmp/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_1") or die "can't copy iopmp program";
          !system("cp $wujian100_open_PATH/case/iopmp/*.h $wujian100_open_PATH/workdir/$MAKE_PATH_2") or die "can't copy iopmp program";
	}
}
print "\nthe case_file is $case_file\n";
print "\nStep2 (Process the command line arguments) is finished!\n";


chdir($work);
$_ = $cpu_model;

if(/e902/){
	!system("cp ../lib/Makefile ./Makefile") or die "cant't copy";
}
else{
	print "Invalid CPU model!";
	exit(1);
}

#将ree库文件中的链接文件和makefile拷贝到工作目录下的ree_lib文件夹中
if(/e902/){
	!system("cp ../lib/$MAKE_PATH_1/Makefile ./$MAKE_PATH_1/Makefile") or die "cant't copy";
        !system("cp ../lib/$MAKE_PATH_1/crt0.s ./$MAKE_PATH_1/crt0.s") or die "cant't copy";
	!system("cp ../lib/$MAKE_PATH_1/linker.lcf ./$MAKE_PATH_1/linker.lcf") or die "cant't copy";
}
else{
	print "Invalid CPU model!";
	exit(1);
}
#将tee库文件中的链接文件和makefile拷贝到工作目录下的tee_lib文件夹中
if(/e902/){
	!system("cp ../lib/$MAKE_PATH_2/Makefile ./$MAKE_PATH_2/Makefile") or die "cant't copy";
        !system("cp ../lib/$MAKE_PATH_2/crt0.s ./$MAKE_PATH_2/crt0.s") or die "cant't copy";
	!system("cp ../lib/$MAKE_PATH_2/linker.lcf ./$MAKE_PATH_2/linker.lcf") or die "cant't copy";
}
else{
	print "Invalid CPU model!";
	exit(1);
}

my $ree_data_addr = 0;
my $tee_data_addr = 0;

if($dahb_lite){
        $ree_data_addr = 00000000;# noted that it is hex format
		$tee_data_addr = 00000000;# noted that it is hex format
}
else{
        $ree_data_addr = 00000000;# noted that it is hex format
		$tee_data_addr = 00000000;# noted that it is hex format
}
#指定两个核心的数据ram起始地址，由于每个核心都访问各自总线上的内存空间，因此不做区分，都设置为相同数值
!system("sed -i 's/DATA_BADDR/0x$ree_data_addr/g' ./$MAKE_PATH_1/linker.lcf") or die "cant't replace";
!system("sed -i 's/DATA_BADDR/0x$tee_data_addr/g' ./$MAKE_PATH_2/linker.lcf") or die "cant't replace";

!system("touch run_case.report") or die "can't touch";
`printf "NOT RUN">run_case.report`;

!system("mkdir ../regress/regress_result");


!system("cp run_case.report ../regress/regress_result/$case_make\.report") or die "can't copy";

#开始make工程
!system("make clean; make all CPU=$cpu_model_make ENDIAN_MODE=little-endian FILE=$case_make HGPR=$hgpr") or die "can't make";
print "make clean; make all CPU=$cpu_model_make ENDIAN_MODE=little-endian FILE=$case_make HGPR=$hgpr\n";
print "\nStep3 (Make) is finished!\n";


my $g_vlib_path;
{
  $g_vlib_path="+libext+.v+.sv+.inc+.h -R";
}
#将新添加ree和tee的总线管理单元（busmnt）和虚拟计数器（virtual_counter）（测试用）添加到编译路径
#新增IOPMP
$g_vlib_path =   $g_vlib_path
 		 ." -v ../tb/tb.v"
		 ." -v ../tb/ree_busmnt.v"
		 ." -v ../tb/tee_busmnt.v"
 		 ." -v ../tb/ree_virtual_counter.v"
		 ." -v ../tb/tee_virtual_counter.v"
		 ." -y ../tb/"
		 ." -v ../soc/sim_lib/*.v"
		 ." -v ../soc/IOPMP/*.v"
         ." -v ../soc/IOPMP/iopmp_config/*.v"
         ." -v ../soc/IOPMP/siopmp/*.v"
         ." -v ../soc/IOPMP/diopmp/*.v"
		 ." -v ../soc/mailbox/*.v"
		 ." -v ../soc/is/*.v"
		 ." -v ../soc/ascon/*.v"
		 ." -v ../soc/flash_ctrl/*.v"
                 ." -v ../soc/*.v";

#添加宏定义头文件路径
my $vcs_incdir = " +incdir+../workdir"

		        ."+../soc/params"
				."+../soc/ascon"
                ."+../soc/IOPMP"
                        ."+../tb";

my  $g_novas_pli;
my  $PLItab;

my $top_mod;
#添加顶层tb文件
  $top_mod = "$wujian100_open_PATH/tb/tb.v ";
if($s_vcs) {
	#启动vcs进行仿真，-full64对于64位的系统必须添加，如果想要更详细的报错，如模块端口信号方向错误等，需要添加选项 +lint=all，注意这类问题都被归结于lint中不属于warning和error
	!system("vcs -gui -full64 +v2k -Mupdate -sverilog +vcs+loopreport $mnt_sim $dump_sim +nospecify +notimingchecks -timescale=1ns/100ps $top_mod   $wujian100_open_PATH/workdir/$had_v $vcs_incdir $g_vlib_path  $PLItab  ") or die "can't run VCS";}
elsif($s_iverilog){
	!system("iverilog -o test.vvp -Diverilog=1 -g2012 ../tb/ree_busmnt.v  ../tb/tb.v ../tb/virtual_counter.v -f ../soc/wujian100_open_syn_for_iverilog.filelist -f ../soc/wujian100_open_lib_for_iverilog.filelist $wujian100_open_PATH/workdir/$had_v") or die "can't run iverilog";
        !system("vvp test.vvp") or die "can't run vvp";
}
else{
  exit(1);
}
print "\nStep4 (Run simulation) is finished\n";

!system("cp run_case.report ../regress/regress_result/$case_make\.report") or die "can't copy";



sub print_usage {
	print << "UseOfrun_case";
Usage: run_case [options] case_name
	[option] =
		[-h]: 
			Print run_case user guider on screen
		[-nodump]:
			Disable the waveform dump function in VCS simulation. If not specified, dump waveform function is enabled
[-sim_tool vcs|iverilog]:      
        		Specify the simulation tools, support vcs and iverilog
		[-nomnt]:
			Disable the monitor module when running tb, monitor is enabled without this option
Example:
	../tools/run_case ../case/addr_map/map_test.c
this command means running case at workdir/ dirctory ,the CPU is RTL code, dumpon the wave from the 0 cycle, and monitor is disabled in tb.

UseOfrun_case
   print "\f";
}
